﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.CodeDom.Compiler;
using System.Diagnostics;
using Microsoft.CSharp;
using System.Windows.Forms;

namespace Generator
{
    public partial class Gramatica
    {
        private string Output = "aSimpleCmp.exe";

        //Generarea codului.
        private string construiesteCod()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(@"using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using ALex2;

                        namespace AnalizorSintactic
                        { 
                            ");
            sb.Append(@"class Program
                        {
                            private static Scaner scaner = new Scaner();
                            private static AtomLexical atomLexical;
                            private static bool eof;

                            static void Main(string[] args)
                            {
                                ");
            sb.Append(@"
                        try
                        {
Console.WriteLine(""Bine ati venit! Introduceti propozitia pe care doriti sa o analizati:"");
                            string propozitie = Console.ReadLine();

                            string fisierSursa = Directory.GetCurrentDirectory() + ""\\src.cs"";
                            File.WriteAllText(fisierSursa,propozitie);

                            scaner = new Scaner();
                            
                            scaner.daFisierSursa(fisierSursa);

                            atomLexical = scaner.nextToken(out eof);

                        ");
            sb.Append("\n"+SimbolStart+
                "();\n\n if(eof==true)\nConsole.WriteLine(\"Succes\");\nelse\n Console.WriteLine(\"Insucces.\");\n"+
                "\nConsole.WriteLine(\"Apasati orice tasta pentru a iesi...\"); \n"+
                " Console.ReadKey();\n}\n catch(Exception exp)\n{\n"+
                "Console.WriteLine(\"Propozitia este incorecta din punct de vedere sintactic.\");\n"+
                "\nConsole.WriteLine(\"Apasati orice tasta pentru a iesi...\"); \n"+
                "Console.ReadKey();\n"+
                "} \n} \n");

            //Generarea functiilor de analiza recursiv descendenta.
            //*****************************************************************************************************************************
            foreach (var Neterminal in Neterminale)
            {
                sb.Append("public static void " + Neterminal + "()\n{\n");

                List<int> reguliFolosite = new List<int>();

                int nrParan1 = 0;
                bool ifAnterior1 = false;

                foreach (var Terminal in listaTerminale)
                {
                    int rp= tabelaLL1.getRule(Neterminal,Terminal);
                    if (rp != -3)
                    {
                        if (ifAnterior1 == true)
                            sb.Append("\n } \n else \n { \n");

                        if (Terminal == "$")
                            sb.Append("if(eof==true) \n { \n");
                        else
                            sb.Append("if(atomLexical.tipAtom == Tokens." + Terminal + ") \n { \n");

                        nrParan1++;
                        ifAnterior1 = true;

                        foreach (var regulaAsociata in reguliProductie)
                        {
                            if (regulaAsociata.numarulRegulii == rp)
                            {
                                int nrParan2 = 0;;
                                foreach (var simbol in regulaAsociata.parteDreaptaRegula)
                                {
                                    if (simbol.esteTerminal == true)
                                    {
                                        if (simbol.val == "$")
                                            sb.Append("if(eof==true) \n { \n");
                                        else
                                            sb.Append("if(atomLexical.tipAtom == Tokens." + simbol.val + ") \n { \n");

                                        sb.Append("if(eof==false)\n { \n");

                                        sb.Append("atomLexical=scaner.nextToken(out eof);\n } else \n  return; \n");

                                        nrParan2++;
                                    }
                                    else
                                        if (simbol.esteNeterminal == true)
                                        {
                                            sb.Append(simbol.val + "();\n");
                                        }
                                        else
                                        {
                                            //epsilon.
                                            if (Terminal == "$")
                                                sb.Append("if(eof==true) \n { \n");
                                            else
                                                sb.Append("if(atomLexical.tipAtom == Tokens." + Terminal + ") \n { \n");

                                            nrParan2++;
                                            break;
                                        }
                                }
                                while (nrParan2 > 0)
                                {
                                    sb.Append("\n } \n else \n throw new Exception(\"Eroare\"); \n");
                                    nrParan2--;
                                }

                            }
                        }
                    }
                    
                }

                if (nrParan1 > 0)
                {
                    sb.Append("\n} \n else \n throw new Exception(\"Eroare\");\n");
                    nrParan1--;
                }
                while (nrParan1 > 0)
                {
                    sb.Append("\n } \n");
                    nrParan1--;
                }

                sb.Append("\n } \n");
            }
                
            //*****************************************************************************************************************************

            sb.Append("\n}  \n } \n");
            string caleFisierDest = Directory.GetCurrentDirectory();
            File.WriteAllText(@caleFisierDest+"\\Program.cs", sb.ToString());

            return sb.ToString();   
        }

        public void genereazaCod()
        {
            string codGenerat = construiesteCod();

            CSharpCodeProvider codeProvider = new CSharpCodeProvider();
            ICodeCompiler icc = codeProvider.CreateCompiler();      

            System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();

            string caleDLL = Directory.GetCurrentDirectory();
            parameters.ReferencedAssemblies.Add(@caleDLL+"\\ALex2.DLL");
            parameters.GenerateExecutable = true;
            parameters.OutputAssembly = Output;

            CompilerResults results = icc.CompileAssemblyFromSource(parameters, codGenerat);

            if (results.Errors.Count > 0)
            {
                foreach (CompilerError CompErr in results.Errors)
                {
                    MessageBox.Show(
                                 "Line number " + CompErr.Line +
                                 ", Error Number: " + CompErr.ErrorNumber +
                                 ", '" + CompErr.ErrorText + ";" +
                                 Environment.NewLine + Environment.NewLine);
                }
            }
            else
            {
                MessageBox.Show("Codul a fost generat cu succes");
               // Process.Start(Output);
            }

        }

        public void executaCod()
        {
            Process.Start(Output);
        }


    }
}
